package cn.akwangl.config;

import cn.akwangl.common.utils.RedisUtils;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * 单集群配置.
 * <p>
 * {@link RedisStandaloneConfiguration}(单节点), {@link RedisSentinelConfiguration}(哨兵), {@link RedisClusterConfiguration} (主从)
 *
 * @author 阿坤同学
 * @date 2022/6/14 14:38
 * @see RedisAutoConfiguration
 * <p>
 * 文献:<br/>
 * <a href="https://www.cnblogs.com/slowcity/p/9002660.html">StringRedisTemplate与RedisTemplate区别点</a><br/>
 * <a href="https://www.cnblogs.com/54chensongxia/p/13815761.html">Redis 客户端 Jedis、lettuce 和 Redisson 对比</a><br/>
 */
@Slf4j
@Configuration
public class RedisConfig {

    @Bean
    public LettuceConnectionFactory lettuceConnectionFactory(RedisProperties redisProperties) {
        // todo 创建RedisConfiguration 需优化,当前配置仅支持单机器
        RedisStandaloneConfiguration redisStandaloneConfiguration = new RedisStandaloneConfiguration();
        redisStandaloneConfiguration.setHostName(redisProperties.getHost());
        redisStandaloneConfiguration.setPort(redisProperties.getPort());
        redisStandaloneConfiguration.setDatabase(redisProperties.getDatabase());
        redisStandaloneConfiguration.setPassword(redisProperties.getPassword());
        LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(redisStandaloneConfiguration);
        log.debug("手动装配 LettuceConnectionFactory地址值:{}", lettuceConnectionFactory);
        log.info("手动装配 LettuceConnectionFactory 初始化完成.");
        return lettuceConnectionFactory;
    }

    /**
     * 构建{@link RedisTemplate},此方法会覆盖{@link RedisAutoConfiguration#redisTemplate(RedisConnectionFactory)}默认实现.
     *
     * @return RedisTemplate
     * @author 阿坤同学
     * @date 2022/6/14 15:55
     * @since 0.0.5
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
        log.debug("手动装配 LettuceConnectionFactory地址值:{}", lettuceConnectionFactory);
        RedisTemplate<String, Object> redisTemplate = createRedisTemplate(lettuceConnectionFactory);
        log.info("手动装配 RedisTemplate 初始化完成.");
        return redisTemplate;
    }

    /**
     * 初始化Redis工具类,简化API调用.
     *
     * @param redisTemplate
     * @return RedisUtils
     * @author 阿坤同学
     * @date 2022/6/14 16:01
     * @since 0.0.5
     */
    @Bean
    public RedisUtils redisUtils(RedisTemplate<String, Object> redisTemplate) {
        RedisUtils redisUtils = new RedisUtils();
        redisUtils.setRedisTemplate(redisTemplate);
        log.info("RedisUtils 初始化完成.");
        return redisUtils;
    }

    /**
     * 创建{@link RedisTemplate}.
     *
     * @param lettuceConnectionFactory 连接工厂.
     * @return RedisTemplate 客户端
     * @author 阿坤同学
     * @date 2022/6/14 15:49
     * @since 0.0.5
     */
    RedisTemplate<String, Object> createRedisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(lettuceConnectionFactory);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        FastJsonRedisSerializer fastJsonRedisSerializer = new FastJsonRedisSerializer(Object.class);
        FastJsonConfig fastJsonConfig = fastJsonRedisSerializer.getFastJsonConfig();
        // 反序列化自动转换为泛型
        fastJsonConfig.setFeatures(Feature.SupportAutoType);
        // 序列化时添加@type字段存储Java完全限定名
        fastJsonConfig.setSerializerFeatures(SerializerFeature.WriteClassName);

        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setValueSerializer(fastJsonRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setHashValueSerializer(fastJsonRedisSerializer);
        return redisTemplate;
    }
}
